import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from tkinter.scrolledtext import ScrolledText
import customtkinter as ctk
import fitz  # PyMuPDF
import os
from pathlib import Path
import threading
from PIL import Image, ImageOps
import sys
import PyPDF2
import traceback
import io  # Import io for byte streams
from modules.converter_mixin import ConverterMixin
from modules.splitter_mixin import SplitterMixin
from modules.img2pdf_mixin import Img2PdfMixin
from modules.merge_mixin import MergeMixin
from modules.watermark_mixin import WatermarkMixin
from modules.word2pdf_mixin import Word2PdfMixin
from modules.excel2pdf_mixin import Excel2PdfMixin
from modules.ui_mixin import UIMixin


class PDFConverter(ctk.CTk,
                   ConverterMixin,
                   SplitterMixin,
                   Img2PdfMixin,
                   MergeMixin,
                   WatermarkMixin,
                   Word2PdfMixin,
                   Excel2PdfMixin,
                   UIMixin):
    def __init__(self):
        super().__init__()

        # 设置主题
        ctk.set_appearance_mode("dark")
        ctk.set_default_color_theme("blue")

        # 配置窗口
        self.title("PDF工具箱")
        self.geometry("700x650")  # 初始大小 (与第一个标签页匹配)
        self.grid_columnconfigure(0, weight=1)
        # Make row 0 (tabview) non-expanding vertically
        self.grid_rowconfigure(0, weight=0)
        # Add an expanding empty row below the tabview to push it up and create bottom space
        self.grid_rowconfigure(1, weight=1)

        # 创建标签页控件
        self.tabview = ctk.CTkTabview(self)
        # Keep pady=20 for consistent padding around the tabview itself
        self.tabview.grid(row=0, column=0, padx=20, pady=20, sticky="nsew")

        # 添加标签页
        self.tab_convert = self.tabview.add("PDF转图片")
        self.tab_split = self.tabview.add("PDF拆分")
        self.tab_merge = self.tabview.add("PDF合并/尺寸统一")
        self.tab_img_to_pdf = self.tabview.add("图片转PDF")
        self.tab_watermark = self.tabview.add("添加水印")  # 新增水印标签页
        self.tab_word2pdf = self.tabview.add("Word转PDF")  # 新增 Word ➜ PDF 标签页
        self.tab_excel = self.tabview.add("Excel转PDF")  # 新增 Excel ➜ PDF 标签页

        # 初始化变量
        self.pdf_paths = []  # 改为列表存储多个PDF路径
        self.output_path = ""
        self.is_converting = False  # 通用转换状态标志
        self.quality = 300  # 默认质量300DPI
        # Word ➜ PDF 相关变量
        self.word_paths = []  # 选中的 Word 文件路径
        self.word_output_path = ""  # Word 转 PDF 输出目录
        self.image_paths = []  # 存储要转换为PDF的图片路径
        self.split_files = []  # 存储要拆分的PDF文件列表
        self.merge_files = []  # 存储要合并的PDF文件/文件夹列表
        # self.is_folder_mode = False # PDF合并是否为文件夹模式 - REMOVED

        # 水印相关变量初始化
        self.watermark_pdf_paths = []  # 存储要添加水印的PDF文件列表
        self.watermark_file_path = ""  # 水印文件路径 (图片或PDF)
        # self.watermark_output_path = "" # 水印输出路径 (使用独立的UI控件获取)
        self.watermark_opacity = tk.DoubleVar(value=0.5)  # 0.0 to 1.0 for fitz
        self.watermark_scale = tk.DoubleVar(value=0.5)  # 1.0 = 100%
        self.watermark_rotation = tk.IntVar(value=0)  # degrees
        self.watermark_position = tk.StringVar(value="居中")  # Position option
        self.watermark_layer = tk.BooleanVar(value=True)  # True for overlay (top layer)

        # Excel ➜ PDF 相关变量
        self.excel_paths = []
        self.excel_output_dir = ""
        
        # PDF转图片输出方式变量
        self.output_mode = None  # 会在create_convert_widgets中初始化

        # 创建各标签页的控件
        self.create_convert_widgets()
        self.create_split_widgets()
        self.create_merge_widgets()
        self.create_img_to_pdf_widgets()
        self.create_watermark_widgets()  # 创建水印控件
        self.create_word2pdf_widgets()  # 创建 Word ➜ PDF 控件
        self.create_excel2pdf_widgets()  # 创建 Excel ➜ PDF 控件

        # 设置标签页切换监听
        self.last_tab = "PDF转图片"
        self.after(100, self.check_tab_change)


    def update_quality(self, value):
        """更新质量值"""
        self.quality = int(value)
        self.quality_label.configure(text=f"图片质量(DPI): {self.quality}")

    def select_pdfs(self):
        """选择多个PDF文件"""
        files = filedialog.askopenfilenames(
            filetypes=[("PDF文件", "*.pdf")]
        )
        if files:
            self.pdf_paths = list(files)
            self.update_file_list()

    def update_file_list(self):
        """更新文件列表显示"""
        self.file_listbox.delete("1.0", tk.END)
        self.file_listbox.insert("1.0", "选择的文件：\n\n")
        for path in self.pdf_paths:
            self.file_listbox.insert(tk.END, f"{os.path.basename(path)}\n")
        # Also display output path if set
        if hasattr(self, 'output_path') and self.output_path:
            if self.tabview.get() == "PDF转图片":
                self.file_listbox.insert(tk.END, f"\n输出文件夹：{self.output_path}\n")
            # Add conditions for other tabs if needed

    def select_output_folder(self):
        """选择输出文件夹"""
        folder = filedialog.askdirectory()
        if folder:
            self.output_path = folder
            self.update_file_list()  # Update listbox to show selected folder

    def start_conversion(self):
        """开始转换流程"""
        if not self.pdf_paths or not self.output_path:
            messagebox.showerror("错误", "请先选择PDF文件和输出文件夹")
            return

        if self.is_converting:
            messagebox.showwarning("提示", "正在进行其他转换，请稍后")
            return

        self.is_converting = True
        self.convert_btn.configure(state="disabled")
        self.status_label.configure(text="正在转换...")
        self.progress_bar.set(0)

        # 在新线程中执行转换
        thread = threading.Thread(target=self.convert_pdfs_thread)  # Use a wrapper
        thread.start()

    # --- Helper methods for thread-safe UI updates ---
    def update_progress_safe(self, progress, status_text):
        """Thread-safe method to update progress bar and status label."""
        if self.progress_bar:
            self.progress_bar.set(progress)
        if self.status_label:
            self.status_label.configure(text=status_text)
        self.update_idletasks()  # Force UI update

    def reset_ui_state(self, button, progress_bar, status_label, status_text="准备就绪"):
        """Thread-safe method to reset UI elements after operation."""
        self.is_converting = False
        if button:
            button.configure(state="normal")
        if progress_bar:
            progress_bar.set(0)
        if status_label:
            status_label.configure(text=status_text)
        self.update_idletasks()

    def show_success_message(self, msg):
        """显示成功消息"""
        messagebox.showinfo("完成", msg)

    def show_error_message(self, error_msg):
        """显示错误消息"""
        messagebox.showerror("错误", f"出现错误：{error_msg}")


    def toggle_range_entry(self):
        """Enable/disable the range entry based on the checkbox state."""
        if self.split_each_page_var.get():
            self.range_entry.configure(state="disabled")
            self.output_name_entry.configure(placeholder_text="文件名将为'原名_第X页'")  # Update placeholder
        else:
            self.range_entry.configure(state="normal")
            self.output_name_entry.configure(placeholder_text="留空则覆盖范围文件")  # Restore placeholder

    def browse_split_files(self):
        """选择要拆分的多个PDF文件"""
        files = filedialog.askopenfilenames(
            title="选择要拆分的PDF文件",
            filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
        )
        if files:
            self.split_files = list(files)
            self.update_split_file_list()

            # 设置默认输出目录为第一个文件的目录
            if self.split_files and not self.split_output_path.get():  # Only set if empty
                default_output = os.path.dirname(self.split_files[0])
                self.split_output_path.set(default_output)

    def update_split_file_list(self):
        """更新PDF拆分文件列表显示"""
        self.split_file_listbox.configure(state="normal")  # Enable editing
        self.split_file_listbox.delete("1.0", tk.END)
        self.split_file_listbox.insert("1.0", "选择的PDF文件：\n\n")
        for path in self.split_files:
            self.split_file_listbox.insert(tk.END, f"{os.path.basename(path)}\n")
        self.split_file_listbox.configure(state="disabled")  # Disable editing

    def browse_split_output(self):
        """选择拆分文件的输出目录"""
        output_path = filedialog.askdirectory(title="选择拆分文件的输出目录")
        if output_path:
            self.split_output_path.set(output_path)

    def parse_page_ranges(self, range_str, max_pages):
        """解析页面范围字符串，返回页码列表 (0-based index)
        支持多种分隔符：空格、逗号、换行等
        """
        pages = set()
        if not range_str:
            return []  # Return empty list if range string is empty

        # 统一使用逗号分隔：将空格、换行等替换为逗号
        import re
        range_str = re.sub(r'[\s,;]+', ',', range_str.strip())
        # 分割多个范围（以逗号分隔）
        parts = range_str.split(",")

        for part in parts:
            part = part.strip()
            if not part: continue  # Skip empty parts

            try:
                if "-" in part:
                    start_str, end_str = part.split("-", 1)  # 只分割第一个连字符
                    start = int(start_str)
                    end = int(end_str)
                    if start < 1 or end > max_pages or start > end:
                        raise ValueError(f"页码范围 '{part}' 无效 (应在 1-{max_pages} 之间且起始页小于等于结束页)")
                    pages.update(range(start - 1, end))  # 0-based index
                else:
                    page = int(part)
                    if page < 1 or page > max_pages:
                        raise ValueError(f"页码 '{page}' 超出范围 (应在 1-{max_pages} 之间)")
                    pages.add(page - 1)  # 0-based index
            except ValueError as e:
                # Re-raise with more context or handle specific conversion errors
                raise ValueError(f"无效的页码或范围: '{part}'. 请使用数字和连字符(例如 1-3 5 7-9 或 1-3,5,7-9)。\n错误: {e}")
            except Exception as e:
                raise ValueError(f"解析页码范围 '{part}' 时发生意外错误: {e}")

        return sorted(list(pages))

    def parse_page_range_groups(self, range_str, max_pages):
        """解析页面范围字符串，返回多个独立的范围组列表
        每个范围组会被拆分成一个单独的PDF文件

        支持输入格式：
        - 空格分隔: "1-5 6-7 8-10"
        - 逗号分隔: "1-5,6-7,8-10"
        - 换行分隔: "1-5\n6-7\n8-10"
        - 混合分隔: "1-5, 6-7 8-10"

        返回: 列表的列表，每个子列表包含一个范围的页码(0-based)
        例如: [[0,1,2,3,4], [5,6], [7,8,9]]
        """
        if not range_str:
            return []

        import re
        # 统一使用逗号分隔：将空格、换行等替换为逗号
        range_str = re.sub(r'[\s,;]+', ',', range_str.strip())
        # 分割多个范围组
        parts = range_str.split(",")

        range_groups = []
        for part in parts:
            part = part.strip()
            if not part:
                continue

            pages = []
            try:
                if "-" in part:
                    start_str, end_str = part.split("-", 1)
                    start = int(start_str)
                    end = int(end_str)
                    if start < 1 or end > max_pages or start > end:
                        raise ValueError(f"页码范围 '{part}' 无效 (应在 1-{max_pages} 之间且起始页小于等于结束页)")
                    pages = list(range(start - 1, end))  # 0-based index
                else:
                    page = int(part)
                    if page < 1 or page > max_pages:
                        raise ValueError(f"页码 '{page}' 超出范围 (应在 1-{max_pages} 之间)")
                    pages = [page - 1]  # 0-based index

                if pages:
                    range_groups.append(pages)

            except ValueError as e:
                raise ValueError(f"无效的页码或范围: '{part}'. 请使用数字和连字符(例如 1-3 5 7-9 或 1-3,5,7-9)。\n错误: {e}")
            except Exception as e:
                raise ValueError(f"解析页码范围 '{part}' 时发生意外错误: {e}")

        return range_groups

    def start_split_pdf(self):
        """启动PDF拆分过程的线程"""
        if not self.split_files:
            messagebox.showerror("错误", "请选择要拆分的PDF文件")
            return

        output_dir = self.split_output_path.get()
        if not output_dir:
            messagebox.showerror("错误", "请选择输出目录")
            return

        if self.is_converting:
            messagebox.showwarning("提示", "正在进行其他转换，请稍后")
            return

        # 根据模式检查输入
        split_each_page = self.split_each_page_var.get()
        range_str = self.range_entry.get().strip() if not split_each_page else ""
        if not split_each_page and not range_str:
            messagebox.showerror("错误", "请输入有效的页面范围 (例如 1-3,5)")
            return

        self.is_converting = True
        self.split_btn.configure(state="disabled")
        self.split_status.configure(text="开始处理...")
        self.split_progress.set(0)

        # 在新线程中执行拆分
        thread = threading.Thread(target=self.split_pdf_thread, args=(output_dir, range_str, split_each_page))
        thread.daemon = True  # Allow closing window even if thread runs
        thread.start()


    def toggle_img_options(self):
        """Show/hide sizing options and change output button text based on conversion mode."""
        if self.conversion_mode.get() == "single":
            self.sizing_frame.grid()  # Show sizing options
            self.select_pdf_output_btn.configure(text="选择输出PDF文件")
            # Output path likely needs to be cleared or re-validated
            prompt = "输出PDF"
        else:  # batch mode
            self.sizing_frame.grid_remove()  # Hide sizing options
            self.select_pdf_output_btn.configure(text="选择输出文件夹")
            prompt = "输出文件夹"

        # Clear output path when mode changes to avoid confusion and update listbox
        self.output_path = ""  # Clear the shared output_path variable
        self.update_image_list(prompt_override=prompt)  # Update listbox with correct prompt

    def select_images(self):
        """选择多个图片文件"""
        files = filedialog.askopenfilenames(
            title="选择图片文件",
            filetypes=[
                ("图片文件", "*.jpg *.jpeg *.png *.bmp *.gif *.tiff *.webp"),  # Added webp
                ("所有文件", "*.*")
            ]
        )
        if files:
            self.image_paths = sorted(list(files))  # Sort naturally
            # Clear output path when new images are selected
            self.output_path = ""
            self.update_image_list()

    def update_image_list(self, prompt_override=None):
        """更新图片列表显示, 包括输出位置"""
        self.image_listbox.configure(state="normal")
        self.image_listbox.delete("1.0", tk.END)
        self.image_listbox.insert("1.0", "选择的图片：\n\n")
        if self.image_paths:
            for path in self.image_paths:
                self.image_listbox.insert(tk.END, f"{os.path.basename(path)}\n")
        else:
            self.image_listbox.insert(tk.END, "(未选择图片)\n")

        # Determine the correct prompt based on mode or override
        prompt = ""
        if prompt_override:
            prompt = prompt_override
        elif self.conversion_mode.get() == "single":
            prompt = "输出PDF"
        else:  # batch
            prompt = "输出文件夹"

        # Display output path/file if set
        self.image_listbox.insert(tk.END, f"\n{prompt}：")
        if hasattr(self, 'output_path') and self.output_path:
            self.image_listbox.insert(tk.END, f"{self.output_path}\n")
        else:
            self.image_listbox.insert(tk.END, "(未选择)\n")

        self.image_listbox.configure(state="disabled")

    def select_pdf_output(self):
        """选择PDF输出位置 (文件或文件夹)"""
        if self.conversion_mode.get() == "single":
            # 单个PDF模式，选择保存文件
            file_path = filedialog.asksaveasfilename(
                title="选择输出PDF文件",
                defaultextension=".pdf",
                filetypes=[("PDF文件", "*.pdf")]
            )
            if file_path:
                # Check if extension is missing and add it
                if not file_path.lower().endswith(".pdf"):
                    file_path += ".pdf"
                self.output_path = file_path
                self.update_image_list(prompt_override="输出PDF")
        else:
            # 批量转换模式，选择输出文件夹
            folder_path = filedialog.askdirectory(title="选择输出文件夹")
            if folder_path:
                self.output_path = folder_path
                self.update_image_list(prompt_override="输出文件夹")

    def start_img_to_pdf_conversion(self):
        """开始图片转PDF转换流程"""
        if not self.image_paths:
            messagebox.showerror("错误", "请先选择图片文件")
            return
        if not self.output_path:
            mode = self.conversion_mode.get()
            msg = "请选择输出PDF文件" if mode == "single" else "请选择输出文件夹"
            messagebox.showerror("错误", msg)
            return

        # Validate output path based on mode
        mode = self.conversion_mode.get()
        if mode == "single" and os.path.isdir(self.output_path):
            messagebox.showerror("错误", "输出应为PDF文件，但选择了文件夹。")
            return
        if mode == "batch" and not os.path.isdir(self.output_path):
            # Check if parent exists, maybe create output dir? For now, error.
            if os.path.exists(self.output_path):
                messagebox.showerror("错误", "输出应为文件夹，但选择了文件。")
            else:
                # Ask user if they want to create the directory?
                # Or just error out. Let's error for simplicity now.
                messagebox.showerror("错误", f"输出文件夹不存在: {self.output_path}")
            return

        if self.is_converting:
            messagebox.showwarning("提示", "正在进行其他转换，请稍后")
            return

        self.is_converting = True
        self.img_convert_btn.configure(state="disabled")
        self.img_status_label.configure(text="正在转换...")
        self.img_progress_bar.set(0)

        # 在新线程中执行转换
        thread = threading.Thread(target=self.convert_images_to_pdf_thread)
        thread.daemon = True
        thread.start()


    def update_merge_file_list(self):
        """更新合并文件/文件夹列表显示，并更新参考PDF下拉菜单"""
        self.file_list_text.configure(state="normal")
        self.file_list_text.delete("1.0", tk.END)
        list_empty = not self.merge_files

        if self.merge_files:
            for i, item_path in enumerate(self.merge_files, 1):
                # 显示基础名称
                base_name = os.path.basename(item_path)
                if not base_name:  # Handle root paths like C:\
                    base_name = item_path
                # prefix = "[文件夹] " if self.is_folder_mode else "" # Mark folders - REMOVED
                display_name = f"{base_name}"

                self.file_list_text.insert(tk.END, f"{i}. {display_name}\n")
        else:
            # placeholder = '(将文件夹拖放到此处或使用"添加文件夹"按钮)' if self.is_folder_mode else '(将PDF文件拖放到此处或使用"添加文件"按钮)' # REMOVED
            placeholder = '(将PDF文件拖放到此处或使用"添加文件"按钮)'  # Simplified placeholder
            self.file_list_text.insert("1.0", placeholder)  # Add placeholder text

        self.file_list_text.configure(state="disabled")  # Disable editing

        # 根据模式更新UI - REMOVED CALL
        # self.toggle_merge_mode_ui()
        # Always show filename entry frame now
        self.merge_name_frame.grid()

        # 更新参考PDF下拉菜单 (仅在文件模式下且勾选统一尺寸时相关)
        # Removed is_folder_mode check
        if self.uniform_size_var.get() and self.size_option.get() == "指定PDF尺寸":
            values = [str(i) for i in range(1, len(self.merge_files) + 1)] if self.merge_files else ["-"]
            current_ref_val = self.reference_pdf_index.get()
            self.reference_pdf_dropdown.configure(values=values)
            # Try to keep the selection if possible, else default to first or "-"
            if current_ref_val in values:
                self.reference_pdf_index.set(current_ref_val)
            elif values and values[0] != "-":
                self.reference_pdf_index.set(values[0])
            else:
                self.reference_pdf_index.set("-")
        elif list_empty:  # Removed or self.is_folder_mode
            # Reset dropdown if list becomes empty
            self.reference_pdf_dropdown.configure(values=["-"])
            self.reference_pdf_index.set("-")

    # def toggle_merge_mode_ui(self): # REMOVED FUNCTION
    #      """根据 is_folder_mode 更新合并标签页的UI元素"""
    #      if self.is_folder_mode:
    #          # --- 文件夹模式 ---
    #          # 隐藏文件名输入
    #          self.merge_name_frame.grid_remove()
    #          # 如果"统一尺寸"被选中，确保"指定PDF"选项不可用
    #          if self.uniform_size_var.get():
    #               current_size_option = self.size_option.get()
    #               # 更新可用选项，移除 "指定PDF尺寸"
    #               available_options = ["第一页尺寸", "A4标准", "自动适应最大"]
    #               self.reference_pdf_dropdown.master.configure(values=available_options) # master is the OptionMenu
    #               # 如果当前选择了 "指定PDF尺寸"，则切换到默认值 "第一页尺寸"
    #               if current_size_option == "指定PDF尺寸":
    #                   self.size_option.set("第一页尺寸")
    #               # 隐藏参考PDF选择器（因为它只为"指定PDF"显示）
    #               self.reference_pdf_frame.pack_forget()

    #      else:
    #          # --- 文件模式 ---
    #          # 显示文件名输入
    #          self.merge_name_frame.grid()
    #           # 恢复"统一尺寸"选项
    #          if self.uniform_size_var.get():
    #                available_options = ["第一页尺寸", "指定PDF尺寸", "A4标准", "自动适应最大"]
    #                self.reference_pdf_dropdown.master.configure(values=available_options)
    #                # 根据当前选项决定是否显示参考PDF选择器
    #                self.update_size_options(self.size_option.get())

    def get_selected_line_index(self):
        """获取当前在文件列表中选中的行的索引 (0-based)"""
        try:
            # Get the start of the selection
            selection_start = self.file_list_text.index(tk.SEL_FIRST)
            # Get the line number (1-based)
            line_number = int(selection_start.split('.')[0])
            # Check if selection is actually on a line with an item number
            line_content = self.file_list_text.get(f"{line_number}.0", f"{line_number}.end")
            # Check if line starts with the line number followed by '.'
            if line_content.strip().startswith(f"{line_number}."):
                return line_number - 1  # Return 0-based index
            else:
                return None  # Selection not on a valid item line
        except tk.TclError:  # No selection
            return None
        except Exception:  # Other potential errors
            return None

    def add_merge_file(self):
        """添加要合并的PDF文件到列表中 (文件模式)"""
        # 切换到文件模式 - REMOVED is_folder_mode check
        # if self.is_folder_mode:
        #      self.merge_files = [] # Clear list when switching mode
        # self.is_folder_mode = False

        files = filedialog.askopenfilenames(
            title="选择要合并的PDF文件",
            filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
        )
        if files:
            added_count = 0
            newly_added_paths = []
            for f in files:
                if f not in self.merge_files:
                    self.merge_files.append(f)
                    newly_added_paths.append(f)
                    added_count += 1

            if added_count > 0:
                self.update_merge_file_list()  # 更新列表和UI
                self.merge_status.configure(text=f"已添加 {added_count} 个文件")
                # 设置默认输出目录 (如果列表之前为空或刚切换模式)
                if len(self.merge_files) == added_count and newly_added_paths:
                    if not self.merge_output_path.get():  # Only set if not already set
                        default_output = os.path.dirname(newly_added_paths[0])
                        self.merge_output_path.set(default_output)
            else:
                self.merge_status.configure(text="选择的文件已在列表中")

    def clear_merge_list(self):  # 重命名函数
        """清空合并列表 (文件或文件夹)"""
        if not self.merge_files: return  # Do nothing if already empty
        self.merge_files = []
        # 不需要手动设置 is_folder_mode，因为它会在添加时设置
        self.update_merge_file_list()  # 更新列表和UI
        self.merge_status.configure(text="列表已清空")

    def move_item_up(self):  # 重命名函数
        """将选中的项目（文件或文件夹）在列表中向上移动一位"""
        selected_index = self.get_selected_line_index()
        if selected_index is not None and selected_index > 0:
            # Swap elements
            self.merge_files[selected_index], self.merge_files[selected_index - 1] = \
                self.merge_files[selected_index - 1], self.merge_files[selected_index]
            self.update_merge_file_list()
            # Reselect the item in its new position (line number selected_index)
            self.select_listbox_line(selected_index)  # 1-based line number

    def move_item_down(self):  # 重命名函数
        """将选中的项目（文件或文件夹）在列表中向下移动一位"""
        selected_index = self.get_selected_line_index()
        if selected_index is not None and selected_index < len(self.merge_files) - 1:
            # Swap elements
            self.merge_files[selected_index], self.merge_files[selected_index + 1] = \
                self.merge_files[selected_index + 1], self.merge_files[selected_index]
            self.update_merge_file_list()
            # Reselect the item in its new position (line number selected_index + 2)
            self.select_listbox_line(selected_index + 2)  # 1-based line number

    def remove_selected_item(self):  # 重命名函数
        """从列表中删除选中的项目（文件或文件夹）"""
        selected_index = self.get_selected_line_index()
        if selected_index is not None:
            removed_item_name = os.path.basename(self.merge_files[selected_index])
            del self.merge_files[selected_index]
            self.update_merge_file_list()
            self.merge_status.configure(text=f"已删除: {removed_item_name}")
            # Optionally select the next item or clear selection
            if self.merge_files:
                new_selection_index = min(selected_index, len(self.merge_files) - 1)  # Select same index or last item
                self.select_listbox_line(new_selection_index + 1)
            elif not self.merge_files:
                # If list becomes empty, ensure UI reflects this possibility
                self.update_merge_file_list()

    def select_listbox_line(self, line_number):
        """Selects a specific line in the file_list_text widget."""
        if line_number < 1: return
        try:
            start_index = f"{line_number}.0"
            end_index = f"{line_number}.end"
            self.file_list_text.tag_remove(tk.SEL, "1.0", tk.END)  # Remove existing selection
            self.file_list_text.tag_add(tk.SEL, start_index, end_index)  # Add new selection
            self.file_list_text.see(start_index)  # Ensure the line is visible
            self.file_list_text.focus_set()  # Give focus to the listbox
        except tk.TclError:
            print(f"无法选择行 {line_number}")  # Error selecting line

    def browse_merge_output(self):
        """选择合并后PDF的输出目录"""
        output_path = filedialog.askdirectory(title="选择合并文件的输出目录")
        if output_path:
            self.merge_output_path.set(output_path)

    def start_merge_pdfs(self):
        """启动PDF合并过程的线程 (仅文件模式)"""
        if not self.merge_files:
            # msg = "请先添加要合并的文件夹" if self.is_folder_mode else "请先添加要合并的PDF文件" # REMOVED
            msg = "请先添加要合并的PDF文件"
            messagebox.showerror("错误", msg)
            return

        output_dir = self.merge_output_path.get()
        if not output_dir:
            messagebox.showerror("错误", "请选择输出目录")
            return

        # 文件模式特定检查 - REMOVED is_folder_mode check
        # if not self.is_folder_mode:
        output_name = self.merge_name_entry.get().strip()
        if not output_name:
            messagebox.showerror("错误", "请输入输出文件名")
            return
            # Basic check for invalid filename chars? Maybe too complex.
        if "/" in output_name or "\\" in output_name:
            messagebox.showerror("错误", "输出文件名不能包含路径分隔符 ( / 或 \\ )")
            return
        # Ensure output filename ends with .pdf
        if not output_name.lower().endswith(".pdf"):
            output_name += ".pdf"
        final_output_path = os.path.join(output_dir, output_name)
        # Check if output file already exists (optional)
        # if os.path.exists(final_output_path):
        #     if not messagebox.askyesno("确认", f"文件 '{output_name}' 已存在。\n是否覆盖?"):
        #         return
        # else:
        #      # 文件夹模式下，输出路径仅为目录，文件名在线程中生成 - REMOVED
        #      final_output_path = output_dir # Pass directory path

        if self.is_converting:
            messagebox.showwarning("提示", "正在进行其他转换，请稍后")
            return

        self.is_converting = True
        self.merge_btn.configure(state="disabled")
        self.merge_status.configure(text="开始处理...")
        self.merge_progress.set(0)

        # Get merge options
        uniform_size = self.uniform_size_var.get()
        size_option = self.size_option.get() if uniform_size else None
        ref_pdf_idx_str = None
        # Removed is_folder_mode check
        if uniform_size and (size_option == "指定PDF尺寸" or size_option == "指定PDF尺寸 (图像)"):
            ref_pdf_idx_str = self.reference_pdf_index.get()

        # Start the thread
        thread = threading.Thread(target=self.merge_pdfs_thread,
                                  args=(final_output_path, uniform_size, size_option,
                                        ref_pdf_idx_str))  # Removed is_folder_mode
        thread.daemon = True
        thread.start()


    def toggle_size_options_visibility(self):
        """Show or hide the size options based on the 'Uniform Size' checkbox."""
        if self.uniform_size_var.get():
            self.size_options_inner_frame.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
            # 更新UI，特别是处理文件夹模式下的限制
            # self.toggle_merge_mode_ui() # 调用这个函数来处理选项的可用性
            # No need to call update_size_options here unless merge_files changed
            # self.update_size_options(self.size_option.get())
        else:
            self.size_options_inner_frame.pack_forget()
            self.reference_pdf_frame.pack_forget()  # Also hide ref PDF frame

    def update_size_options(self, option):
        """当选择尺寸选项变化时更新UI (特别是 参考PDF 下拉菜单)"""
        # 仅在文件模式下且勾选了统一尺寸时才处理参考PDF - REMOVED is_folder_mode check
        # if not self.is_folder_mode and self.uniform_size_var.get() and option == "指定PDF尺寸":
        if self.uniform_size_var.get() and (option == "指定PDF尺寸" or option == "指定PDF尺寸 (图像)"):
            # Update reference PDF dropdown options
            values = [str(i) for i in range(1, len(self.merge_files) + 1)] if self.merge_files else ["-"]
            current_ref_val = self.reference_pdf_index.get()

            # Check if the dropdown exists before configuring
            if hasattr(self, 'reference_pdf_dropdown'):
                self.reference_pdf_dropdown.configure(values=values)
                # Try to keep selection
                if current_ref_val in values:
                    self.reference_pdf_index.set(current_ref_val)
                elif values and values[0] != "-":
                    self.reference_pdf_index.set(values[0])
                else:
                    self.reference_pdf_index.set("-")

                # Show the frame
                self.reference_pdf_frame.pack(side=tk.LEFT, padx=(10, 5))  # Pack it here
            else:
                print("警告: reference_pdf_dropdown 不存在")

        else:
            # Hide reference PDF frame if it exists and we are not in the '指定PDF尺寸' case
            if hasattr(self, 'reference_pdf_frame'):
                self.reference_pdf_frame.pack_forget()
            # No warning needed if it doesn't exist


    def update_wm_opacity_label(self, value):
        self.wm_opacity_label.configure(text=f"{int(float(value) * 100)}%")

    def update_wm_scale_label(self, value):
        self.wm_scale_label.configure(text=f"{int(float(value) * 100)}%")

    def update_wm_rotate_label(self, value):
        self.wm_rotate_label.configure(text=f"{int(float(value))}°")

    def select_watermark_pdfs(self):
        """选择要添加水印的目标PDF文件"""
        files = filedialog.askopenfilenames(
            title="选择目标PDF文件",
            filetypes=[("PDF文件", "*.pdf")]
        )
        if files:
            self.watermark_pdf_paths = list(files)
            self.update_watermark_pdf_list()
            # Set default output folder if not already set
            if self.watermark_pdf_paths and not self.watermark_output_entry.get():
                default_output = os.path.dirname(self.watermark_pdf_paths[0])
                self.watermark_output_entry.insert(0, default_output)

    def update_watermark_pdf_list(self):
        """更新水印目标PDF文件列表显示"""
        self.watermark_pdf_listbox.configure(state="normal")
        self.watermark_pdf_listbox.delete("1.0", tk.END)
        if self.watermark_pdf_paths:
            self.watermark_pdf_listbox.insert("1.0", "目标 PDF 文件列表:\n\n")
            for path in self.watermark_pdf_paths:
                self.watermark_pdf_listbox.insert(tk.END, f"{os.path.basename(path)}\n")
        else:
            self.watermark_pdf_listbox.insert("1.0", "目标 PDF 文件列表:\n(未选择)")
        self.watermark_pdf_listbox.configure(state="disabled")

    def select_watermark_file(self):
        """选择水印文件（图片或PDF）"""
        file = filedialog.askopenfilename(
            title="选择水印文件",
            filetypes=[
                ("图片或PDF", "*.png *.jpg *.jpeg *.bmp *.tiff *.pdf"),
                ("图片文件", "*.png *.jpg *.jpeg *.bmp *.tiff"),
                ("PDF 文件", "*.pdf"),
                ("所有文件", "*.*")
            ]
        )
        if file:
            self.watermark_file_path = file
            self.watermark_file_label.configure(text=f"水印文件: {os.path.basename(file)}")

    def select_watermark_output_folder(self):
        """选择水印处理后的PDF输出目录"""
        folder = filedialog.askdirectory(title="选择输出目录")
        if folder:
            # self.watermark_output_path = folder # 存储到类变量中（如果其他地方需要原始路径）
            self.watermark_output_entry.delete(0, tk.END)
            self.watermark_output_entry.insert(0, folder)

    def start_watermarking(self):
        """启动添加水印过程的线程"""
        # 1. Validate inputs
        if not self.watermark_pdf_paths:
            messagebox.showerror("错误", "请选择要添加水印的目标PDF文件")
            return
        if not self.watermark_file_path:
            messagebox.showerror("错误", "请选择水印文件 (图片或PDF)")
            return
        if not os.path.exists(self.watermark_file_path):
            messagebox.showerror("错误", f"水印文件不存在:\n{self.watermark_file_path}")
            return

        output_dir = self.watermark_output_entry.get()
        if not output_dir:
            messagebox.showerror("错误", "请选择输出目录")
            return
        if not os.path.isdir(output_dir):
            try:
                # Attempt to create the directory
                os.makedirs(output_dir)
                print(f"创建输出目录: {output_dir}")
            except Exception as e:
                messagebox.showerror("错误", f"无法创建输出目录:\n{output_dir}\n{e}")
                return

        if self.is_converting:
            messagebox.showwarning("提示", "正在进行其他转换，请稍后")
            return

        # 2. Get settings
        settings = {
            "opacity": self.watermark_opacity.get(),
            "scale": self.watermark_scale.get(),
            "rotation": self.watermark_rotation.get(),
            "position": self.watermark_position.get(),
            "overlay": self.watermark_layer.get(),  # True for top layer
            "suffix": self.watermark_suffix_entry.get().strip(),
            "output_dir": output_dir
        }

        # Validate suffix (prevent replacing original if suffix is empty?)
        if not settings["suffix"]:
            if not messagebox.askyesno("确认", "输出后缀为空，这可能会覆盖原始文件。\n确定要继续吗？"):
                return

        # 3. Prepare for threading
        self.is_converting = True
        self.watermark_btn.configure(state="disabled")
        self.watermark_status_label.configure(text="开始添加水印...")
        self.watermark_progress_bar.set(0)

        # 4. Start thread
        thread = threading.Thread(target=self.add_watermarks_thread, args=(settings,))
        thread.daemon = True
        thread.start()


if __name__ == "__main__":
    # customtkinter 会自动处理 DPI 缩放，无需手动设置
    app = PDFConverter()
    app.mainloop()
